package com.yjzx.util.common.util.excel.alibaba;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.yjzx.util.common.util.collection.EmptyUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author yjzx
 * @date 2024/8/18
 * @description excel监听类
 */
@Slf4j
public class ExcelListener<T> extends AnalysisEventListener<T> {

    /**
     * <p>存放读取后的数据</p >
     *
     * @date 2021/9/2 0:10
     */
    public List<T> datas = new ArrayList<>();

    public final List<List<String>> head;

    private final List<Map<Integer,String>> headTemp = new ArrayList<>();

    public ExcelListener(Class<T> t) {
        this.head = ExcelListener.classToExcelHead(t);
    }

    public ExcelListener(List<String>... heads) {
        this.head = Arrays.asList(heads);
    }

    public ExcelListener(List<List<String>> heads) {
        this.head = heads;
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        if (this.head!=null&&this.head.size()>0){
            headTemp.add(headMap);
            int row = headTemp.size();
            List<String> list = this.head.get(row - 1);

            if (EmptyUtils.isNotEmpty(list)) {
                String h1, h2;
                for (int i = 0; i < list.size(); i++) {
                    h1 = list.get(i);
                    h2 = headMap.get(i);
                    if (h1 == null || !Objects.equals(h1, h2)) {
                        throw new ExcelAnalysisException("模板列名不一致,请重新导出模板使用；第"+row+"行，第" + (i+1) + "列("+EasyExcelUtil.getRowName(i+1)+"):(最新模板列名):" + h1 + ";(你使用的模板列名):" + h2 );
                    }
                }
            }
        }


    }

    /**
     * <p>读取数据，一条一条读取</p >
     *
     * @date 2021/9/2 0:15
     */
    @Override
    public void invoke(T t, AnalysisContext analysisContext) {
        datas.add(t);
    }

    /**
     * <p>解析完毕之后执行</p >
     *
     * @date 2021/9/2 0:06
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("读取数据条数：{}条！", datas.size());
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        //重新构造数据转化异常
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException convertEx = (ExcelDataConvertException) exception;
            String errorMsg = "第" + (convertEx.getRowIndex() + 1) + "行，第" + (convertEx.getColumnIndex() + 1) + "列格式解析异常";
            exception.printStackTrace();
            throw new ExcelAnalysisException(errorMsg);
        }
        super.onException(exception, context);
    }
    public List<T> getDataList() {
        return Collections.unmodifiableList(this.datas);
    }

    public static List<List<String>> classToExcelHead(Class<?> clazz) {
        List<List<String>> list = null;
        if (clazz != null && (!clazz.isAssignableFrom(Collection.class) || !clazz.isAssignableFrom(Map.class))) {
            Field[] fields = clazz.getDeclaredFields();

            HashMap<Integer, Map<Integer,String>> colRowMap = new HashMap<>(4);
            int row,col;
            row = col = 0;
            for (Field field : fields) {
                field.setAccessible(true);
                ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                if (annotation != null) {
                    int index = annotation.index();
                    col = Math.max(col, index);

                    Map<Integer,String> colMap;
                    if (!colRowMap.containsKey(index)) {
                        colMap = new HashMap<>(16);
                        colRowMap.put(index, colMap);
                    }else {
                        colMap = colRowMap.get(index);
                    }
                    String[] values = annotation.value();
                    row = Math.max(row, values.length);
                    for (int i = 0; i < values.length; i++) {
                        colMap.put(i, values[i]);
                    }

                }
            }
            list = new ArrayList<>();
            for (int i = 0; i < row; i++) {
                for (int i1 = 0; i1 < col; i1++) {
                    Map<Integer, String> rowMap = colRowMap.get(i1);
                    List<String> rows =list.size()<=i ? new ArrayList<>() : list.get(i);
                    list.add(rows);
                    rows.add(rowMap.get(i));
                }
            }
        }
        return list;
    }

}
